
#include <stdio.h>  // 提供输入输出函数（如printf、fprintf）
#include <stdlib.h> // 提供动态内存管理函数（如malloc、realloc、free）
#include <string.h> // 提供字符串操作函数（如strcpy、strcat）

/*
内存类型：区分栈内存（name，固定大小、自动释放）和堆内存（description，动态大小、手动管理）。
动态内存流程：malloc分配 → 检查NULL → 使用（strcpy）→ realloc调整大小 → 检查NULL → 继续使用（strcat）→ free释放。
安全要点：所有动态内存操作（malloc/realloc）必须检查返回值，避免空指针访问；
    字符串操作（strcpy/strcat）需确保目标内存足够大，防止缓冲区溢出。
*/
int main()
{
    char name[100];    // 栈上分配的字符数组（固定大小100字节）
    char *description; // 指向堆内存的字符指针（动态大小）

    // strcpy(dest, src)：字符串复制函数，将src内容复制到dest指向的内存。
    // 由于name是栈上的固定大小数组（100字节），足以容纳字符串"Zara Ali"（长度7+1结束符=8字节），无溢出风险
    strcpy(name, "Zara Ali");

    // 分配30字节堆内存，返回首地址给description
    // description = malloc(30 * sizeof(char));
    description = calloc(30, sizeof(char));

    // 检查内存分配是否失败
    if (description == NULL)
    {
        fprintf(stderr, "Error - unable to allocate required memory\n");
    }
    else
    {
        // 分配成功，复制字符串到堆内存
        strcpy(description, "Zara ali a DPS student.");
    }

    // 将原内存块大小调整为100字节
    // realloc(ptr, new_size)：调整ptr指向的堆内存块大小为new_size字节。可能的行为：
    // 若原内存块后有足够空间，直接扩展并返回原地址；
    // 若空间不足，分配新内存块并复制原数据，释放旧块，返回新地址；
    // 若分配失败，返回NULL，原内存块保持不变（但此代码未保留原指针，存在潜在内存泄漏风险）。
    description = realloc(description, 100 * sizeof(char));

    // 检查重分配是否失败
    if (description == NULL)
    {
        fprintf(stderr, "Error - unable to allocate required memory\n");
    }
    else
    {
        // 重分配成功，追加字符串
        // strcat(dest, src)：字符串追加函数，将src内容添加到dest末尾（需确保dest有足够空间）。
        // 此处description已扩容至100字节，原字符串长度22 + 追加字符串长度19 = 41字节，空间充足
        strcat(description, "She is in class 10th");
    }

    printf("Name = %s\n", name);              // 输出栈内存中的name
    printf("Description: %s\n", description); // 输出堆内存中的description

    // free(ptr)：释放ptr指向的堆内存（必须是malloc/realloc分配的有效指针），避免内存泄漏。
    // name是栈内存（自动存储），函数结束后由系统自动释放，无需手动free
    free(description); // 释放堆内存，避免内存泄漏
}
